home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / listings / v_12_12 / guthrie / xlate.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-09-25  |  19.5 KB  |  488 lines

  1. /**************************************************************************
  2. *  File Name     : XLATE.C
  3. *  Description   : Text Substitution Software tool for Multi Language
  4. *                  Support.
  5. *  Author        : R. Scott Guthrie  /  All Rights Reserved
  6. *  History       : 01/13/94 - Modification to add Speed-Up code for
  7. *                             loading '.TRB' files.
  8. *                  01/20/94 - Function names changed to avoid possible
  9. *                             conflicts with users code.
  10. **************************************************************************/
  11. /*  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  12.  *   Function       : XlateSet() 
  13.  *   Arguments      : (char *) File name of translation file (without ext).
  14.  *   Return         : None
  15.  *   Description    : USER CALLABLE - This function sets the file name
  16.  *                    to be used for string translation.
  17.  *                    If user does not call this function, the translate
  18.  *                    system will use the default file specified in
  19.  *                    constant 'DefaultFileName'.  No checking for
  20.  *                    file existance is performed by this function.
  21.  *   ---------------
  22.  *   Function       : Xlate() 
  23.  *   Arguments      : (char *) String to be translated.
  24.  *   Return         : (char *) Translation string.
  25.  *   Description    : USER CALLABLE - This function translates the string
  26.  *                    passed in, to the translated version in the translate
  27.  *                    table.  If the table has not been loaded, it
  28.  *                    initiates that action before attempting the
  29.  *                    translation.  If no match is found, then a '?' is
  30.  *                    returned.
  31.  *   ---------------
  32.  *   Function       : XlateLoad() 
  33.  *   Arguments      : (char *) File name of translation file.
  34.  *   Return         : (int) function status
  35.  *   Description    : INTERNAL FUNCTION - Called by 'Xlate()' to build the
  36.  *                    translation table.
  37.  *   ---------------
  38.  *   Function       : XlateLoadBinary() 
  39.  *   Arguments      : (FILE) File Descriptor of the binary translation file.
  40.  *   Return         : (int) function status
  41.  *   Description    : INTERNAL FUNCTION - Called by 'XlateLoad()' to
  42.  *                    load the binary translation table from a TRB file.
  43.  *   ---------------
  44.  *   Function       : XlateLoadText() 
  45.  *   Arguments      : (FILE) File descriptor of the Text translation file.
  46.  *   Return         : (int) function status
  47.  *   Description    : INTERNAL FUNCTION - Called by 'XlateLoad()' to
  48.  *                    build and load the translation table from a TRN file.
  49.  *   ---------------
  50.  *   Function       : XlateFree() 
  51.  *   Arguments      : None
  52.  *   Return         : None
  53.  *   Description    : USER CALLABLE - This function is used to free the
  54.  *                    memory allocated for the TRANSLATE system. It is used
  55.  *                    internally and callable directly.
  56.  *   ---------------
  57.  *   Function       : XlateSearchCompare()
  58.  *   Arguments      : (const void *) Pointer to compare string 1.
  59.  *                    (const void *) Pointer to compare string 2.  
  60.  *   Return         : (int) Compare status
  61.  *   Description    : INTERNAL FUNCTION - Search Compare Function.
  62.  *   ---------------
  63.  *   Function       : XlateSortCompare()
  64.  *   Arguments      : (const void *) Pointer to compare string 1.
  65.  *                    (const void *) Pointer to compare string 2.
  66.  *   Return         : (int) Compare status
  67.  *   Description    : INTERNAL FUNCTION - Sort Compare Function.
  68.  *   ---------------
  69.  *   Function       : XlateGetString() 
  70.  *   Arguments      : (FILE) File descriptor of the Text translation file.
  71.  *                    (char *) Pointer to a string.
  72.  *   Return         : (int) Number of characters in string or -1 for EOF 
  73.  *   Description    : INTERNAL FUNCTION - Called by 'XlateLoadText()'
  74.  *                    Reads and parses through the TRN file and returns
  75.  *                    the next String value found.
  76.  *   ---------------
  77.  *   Function       : XlateCreateTable()
  78.  *   Arguments      : (int) Number of XLATE entries.
  79.  *   Return         : (int) 1 for success, -1 for Allocation Error. 
  80.  *   Description    : INTERNAL FUNCTION - Called by 'XlateLoadText()'
  81.  *                    and 'XlateLoadBinary()' to allocate memory
  82.  *                    for the Translate Table.
  83.  *  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
  84.  
  85. #include <stdio.h>
  86. #include <stdlib.h>
  87. #include <string.h>
  88. #include <io.h>
  89. #include <fcntl.h>
  90. #include <alloc.h>
  91. #include <assert.h>
  92. #include "xlate.h"
  93.  
  94. /* GLOBAL VARAIBLES */
  95. XLATE  *XlateBase = NULL;
  96. int    XlateLines = 0;
  97. char   *XlateFile = XlateDefaultFileName;
  98.  
  99. /* FUNCTION DEFINITIONS */
  100. /*========================================*/
  101.   void XlateSet(char *translate_file_name)
  102. /*========================================*/
  103. /* Establish Translation Table Name */
  104. {
  105.   XlateFree();                        /* clear any existing table */
  106.   XlateFile = translate_file_name;    /* set to new file name. */
  107.   return;
  108. } /* end function 'XlateSet()' */
  109.  
  110. /*=============================*/
  111.   char *Xlate(char *key_string)
  112. /*=============================*/
  113. /* Translate a given KEY string to a Translated version by searching */
  114. /* through the Translation table. */
  115. {
  116.   XLATE *node;                        /* Allocate pointer to an XLATE node */
  117.   static char Default[] = "?";        /* Default String */
  118.  
  119.   /* If the translation file has not been read in, then load it. */
  120.   if(!XlateBase)
  121.     (void) XlateLoad(XlateFile);
  122.  
  123.   if(!XlateBase)                      /* If file wasn't loaded (found), */
  124.     return(Default);                  /* Return the default string */
  125.  
  126.   /* Search translation block for matching key string. */
  127.   if((node = (XLATE *)bsearch(key_string, XlateBase,
  128.       XlateLines, sizeof(XLATE), XlateSearchCompare)) == NULL)
  129.     return(Default);                  /* If no KEY is found */
  130.  
  131.   /* Return pointer to the translated value. */
  132.   return(node->translated_value);
  133.  
  134. } /* end function 'Xlate()' */
  135.  
  136. /*=============================*/
  137.   int XlateLoad(char *filename)
  138. /*=============================*/
  139. /* This function is used to load a translation definition file.  */
  140. /* Returns the number of Translate Table Entires or:             */
  141. /*    0 if no file is found. (either ".TRB" or ".TRN")           */
  142. /*   -1 if memory allocation error encountered.                  */
  143. {
  144.   char  filenamebuf[128];       /* Filename Buffer */
  145.   FILE  *fd;                    /* Translation File Descriptor */
  146.   int retval = 0;               /* return variable */
  147.  
  148.   /* Delete any existing 'in memory' translate table */
  149.   XlateFree();
  150.  
  151.   /* Attempt to open a Binary Version of the translate file. */
  152.   sprintf(filenamebuf, "%s.TRB", filename);
  153.   if((fd = fopen(filenamebuf, "rb")) != NULL)
  154.   {
  155.     retval = XlateLoadBinary(fd);
  156.     fclose(fd);                      /* Finished with file */
  157.   }
  158.   else                               /* Binary file did not open */
  159.   {
  160.     /* Attempt to open a Text Version of the translate file. */
  161.     sprintf(filenamebuf, "%s.TRN", filename);
  162.     if((fd = fopen(filenamebuf, "r")) != NULL)
  163.     {
  164.       retval = XlateLoadText(fd);
  165.       fclose(fd);                    /* Finished with file */
  166.     }
  167.   }
  168.   /* If there was an error, then free any memory that did happen */
  169.   /* to get allocated for the table and any Keys or Results.     */
  170.   if(retval <= 0)
  171.     XlateFree();
  172.  
  173.   return(retval);
  174. }  /* end 'XlateLoad()' */
  175.  
  176. /*=============================*/
  177.   int XlateLoadBinary(FILE *fd)
  178. /*=============================*/
  179. /* Loads the binary version of the translate file.  This loads */
  180. /* faster than the Text version.                               */
  181. {
  182.   /* Binary File format is:                          */
  183.   /*  4 bytes = ".TRB"  (File Signature)             */
  184.   /*  integer # of lines                             */
  185.   /*  integer # of line sets of:                     */
  186.   /*    integer size of key string                   */
  187.   /*    null terminated key string                   */
  188.   /*    integer size of result string                */
  189.   /*    null terminated result string                */
  190.   /*  (Note: The file is pre-sorted by Key Strings)  */
  191.  
  192.   char signature[5];  /* buffer for signature string */
  193.   int i;              /* Loop Variable */
  194.   int length;         /* string length read from file */
  195.   XLATE *node;        /* Allocated Node */
  196.  
  197.   /* Get the file Signature */
  198.   if(fread(signature, 4 * sizeof(char), 1, fd) != 1)
  199.     return 0;              /* Bad read from File */
  200.   signature[4] = '\0';     /* terminating NULL for signature string */
  201.   if(strcmp(signature, ".TRB") != 0)
  202.     return 0;              /* Not a ".TRB" Binary Translate File */
  203.  
  204.   /* Get the number of entries */
  205.   if(fread(&XlateLines, sizeof(XlateLines), 1, fd) != 1)
  206.     return 0;             /* File Error - No Size Found. */
  207.  
  208.   /* Allocate the translate table memory */
  209.   if(XlateCreateTable(XlateLines) == -1)
  210.     return (-1);          /* Allocation Error */
  211.  
  212.   node = XlateBase;       /* point node to the table */
  213.  
  214.   for(i=0; i< XlateLines; i++)
  215.   {
  216.     /* PROCESS KEY VALUE */
  217.     /* Get Length of Key Value */
  218.     if(fread(&length, sizeof(length),1,fd) != 1)
  219.       return(0);  /* File Error - No Length Found. */
  220.  
  221.     /* Allocate Key String space */
  222.     if((node->translate_key = (char*)malloc(sizeof(char) * length)) == NULL)
  223.       return(-1);         /* File Error - Allocation Failed */
  224.  
  225.     /* Read Key String into translate table */
  226.  
  227.     if(fread(node->translate_key, length, 1, fd) != 1)
  228.       return(0);          /* File Error - String not read correctly */
  229.  
  230.     /* PROCESS RESULT VALUE */
  231.     /* Get Length of Result Value */
  232.     if(fread(&length, sizeof(length),1,fd) != 1)
  233.       return(0);          /* File Error - No Length Found. */
  234.  
  235.     /* Allocate Result String space */
  236.     if((node->translated_value = (char*)malloc(sizeof(char) * length)) == NULL)
  237.       return(-1);         /* File Error - Allocation Failed */
  238.  
  239.     /* Read Result String into translate table */
  240.     if(fread(node->translated_value, length, 1, fd) != 1)
  241.       return(0);          /* File Error - String not read correctly */
  242.  
  243.     node++;               /* Bump Node Pointer */
  244.   }
  245.   return(XlateLines);
  246. } /* end 'XlateLoadBinary()' */
  247.  
  248. /*=======================================*/
  249.   int XlateGetString(FILE *fd, char *str)
  250. /*=======================================*/
  251. /* Parser State Machine's Operation and Rules                          */
  252. /*                                                                     */
  253. /* - Text Delimeters are square brackets. '[' and ']'                  */
  254. /* - 'Strings' are text values within delimeters.                      */
  255. /* - Whitespace is ignored except within Strings.                      */
  256. /* - Key and Result values are Strings.                                */
  257. /* - Any non-string text is ignored. (Considered a comment)            */
  258. /* - Delimeters can be escaped with backslash '\' character.           */
  259. /* - Backslash can be escaped with Blackslash. '\\'                    */
  260. /* - Key and Result values are interpreted as a Pair of Strings.       */
  261. /*   ( [Key value] followed by [Result value] )                        */
  262. /* - The Key value and the Result value need not be on the same line,  */
  263. /*   but must be contigious.                                           */
  264. /* - String values can be split across multiple lines, but newline     */
  265. /*   characters are NOT preserved.                                     */
  266. /* - String lengths will be truncated to 'XlateMaxLength' characters.  */
  267. /*                                                                     */
  268. /* Returns: Length of string returned, or -1 for EOF                   */
  269. {
  270.   /* Define State Types */
  271.   enum {WhiteSpace, String, WhiteSpaceEscape,
  272.     Escape, Truncate, TruncateEscape};
  273.  
  274.   int count;                         /* # of characters copied to str */
  275.   int state = WhiteSpace;            /* Current State of Parser */
  276.   char *pos;                         /* Current position in str */
  277.   char ch;                           /* Character being processed */
  278.  
  279.   count = 0;
  280.   while((ch = (char) fgetc(fd)) != (char)EOF)
  281.   {
  282.     /* Test for full buffer */
  283.     if(count == XlateMaxLength - 1)  /* If the buffer is full,    */
  284.       state = Truncate;              /* change state to Truncate. */
  285.  
  286.     switch(state)
  287.     {
  288.       case WhiteSpace:               /* PROCESS WHITE SPACE */
  289.     switch(ch)                   /* switch on char received */
  290.     {
  291.       case XlateOpenDelimeter:
  292.         pos = str;               /* Position to beginning of str */
  293.         count = 0;               /* zero the count value */
  294.         state = String;          /* Change state */
  295.         break;
  296.       case XlateEscapeCharacter: /* Escape Character encountered */
  297.         state = WhiteSpaceEscape;
  298.         break;
  299.       default:                   /* ignore all other characters */
  300.         break;
  301.     }
  302.     break;
  303.  
  304.       case String:                   /* PROCESS STRING VALUE */
  305.     switch(ch)                   /* switch on char received */
  306.     {
  307.       case XlateCloseDelimeter:  /* Close Delimeter encountered */
  308.         *pos = '\0';             /* terminate buffer */
  309.         return count;            /* return string length */
  310.       case XlateEscapeCharacter: /* Escape Character encountered */
  311.         state = Escape;          /* Change state */
  312.         break;
  313.       case '\n':                 /* Ignore newline character */
  314.         break;
  315.       default:                   /* Other character encountered */
  316.         *pos++ = ch;             /* Copy char to the buffer */
  317.         count++;                 /* Bump character count */
  318.         break;
  319.     }
  320.     break;
  321.  
  322.       case WhiteSpaceEscape:         /* Ignore character found */
  323.     state = WhiteSpace;          /* after an escape while  */
  324.     break;                       /* scanning WhiteSpace.   */
  325.  
  326.       case Escape:                   /* PROCESS ESCAPE */
  327.     *pos++ = ch;                 /* Copy whatever it is... */
  328.     count++;                     /* bump character count */
  329.     state = String;              /* reset to String State */
  330.     break;
  331.  
  332.       case Truncate:                 /* Don't Copy Characters */
  333.     switch(ch)                   /* switch on char received */
  334.     {
  335.       case XlateCloseDelimeter:  /* Close Delimeter encountered */
  336.         *pos = '\0';             /* terminate buffer */
  337.         return count;            /* return string length */
  338.       case XlateEscapeCharacter: /* Escape Character encountered */
  339.         state = TruncateEscape;  /* Change state to process Escape */
  340.         break;
  341.       default:                   /* Other Character encountered */
  342.         break;                   /* Do Nothing... */
  343.     }
  344.         break;                       /* Break Truncate Case */
  345.  
  346.       case TruncateEscape:           /* Ignore character found */
  347.     state = Truncate;            /* after an escape while  */
  348.     break;                       /* Truncating.            */
  349.  
  350.       default:
  351.     assert(0);                   /* unreachable code */
  352.     break;
  353.  
  354.     }  /* end switch 'state' */
  355.   }  /* end while '!EOF' */
  356.  
  357.   *str = '\0';                       /* Return NULL in str */
  358.     
  359.   return(-1);                        /* EOF reached */
  360. } /* end 'XlateGetString()' */
  361.  
  362. /*===========================*/
  363.   int XlateLoadText(FILE *fd)
  364. /*===========================*/
  365. /* This function is used to load a translation definition file. */
  366. /* Returns the number of lines processed or:                    */
  367. /*   0  if no such file, or                                     */
  368. /*  -1 Out of Memory or other memmory allocation error.         */
  369. {
  370.   char  buffer[XlateMaxLength];      /* Text Buffer (data from file) */
  371.   int   i;                           /* Local Index Variable */
  372.   XLATE *node;                       /* Translate Node */
  373.   int   length;                      /* Length of string */
  374.  
  375.   /* PASS 1 - Begin Processing */
  376.   XlateLines = 0;                    /* Initialize string count. */
  377.  
  378.   /* Count number of String Values */
  379.   while(XlateGetString(fd, buffer) >= 0)     /* returns -1 at EOF */
  380.     XlateLines++;
  381.  
  382.   /* XlateLines = number of strings found. (Half are Keys and Half   */
  383.   /* are Results) If there isn't an even number, then there won't be */
  384.   /* a Result value for the last Key value. (or someone mis-counted) */
  385.  
  386.   if((XlateLines % 2) == 1)          /* (Last Key value will be   */
  387.     XlateLines--;                    /* ignored since there is no */
  388.   XlateLines /= 2;                   /* Result value for it.)     */
  389.  
  390.   /* PASS 2 - Build in-memory table */
  391.   /* Reset the translation file (to the top) */
  392.   rewind(fd);
  393.  
  394.   /* Allocate the translate table memory */
  395.   if(XlateCreateTable(XlateLines) == -1)
  396.     return (-1);                     /* Allocation Error */
  397.  
  398.   /* Read the file entries into the Translate Table. */
  399.   node = XlateBase;                  /* establish pointer to table */
  400.   for(i = 0; i < XlateLines; i++)    /* Loop for number of lines */
  401.   {
  402.     /* Get KEY value */
  403.     length = XlateGetString(fd, buffer);
  404.  
  405.     /* Store KEY value in the table */
  406.     if((node->translate_key = (char *)malloc(sizeof(char) *
  407.                   (length + 1))) == NULL)
  408.       return(-1);                    /* Allocation Error */
  409.     strcpy(node->translate_key, buffer);  /* Move Value to Table */
  410.  
  411.     /* Get RESULT value */
  412.     length = XlateGetString(fd, buffer);
  413.  
  414.     /* Store RESULT value in the table */
  415.     if((node->translated_value = (char *)malloc(sizeof(char) *
  416.                  (length + 1))) == NULL)
  417.       return(-1);                    /* Allocation Error */
  418.     strcpy(node->translated_value, buffer);
  419.  
  420.     node++;                          /* Advance Table Pointer */
  421.   }  /* end 'for loop' */
  422.  
  423.   /* Sort the TRANSLATE Block. */
  424.   qsort(XlateBase, XlateLines, sizeof(XLATE), XlateSortCompare);
  425.  
  426.   return(XlateLines);                /* good return */
  427.  
  428. } /* end function 'XlateLoadText' */
  429.  
  430. /*=================================*/
  431.   int XlateCreateTable(int entries)
  432. /*=================================*/
  433. {
  434.   /* Allocate space for the file entries (XLATE structures) */
  435.   if((XlateBase = (XLATE *) malloc(sizeof(XLATE) * entries)) == NULL)
  436.     return (-1);  /* return memory allocation error */
  437.   memset(XlateBase, 0, (sizeof(XLATE) * entries));  /* zero table */
  438.   return (1);
  439. }
  440.  
  441. /*====================*/
  442.   void XlateFree(void)
  443. /*====================*/
  444. /* Free allocated translate table (if any) */
  445. {
  446.   XLATE *node;                           /* Translate Node Pointer */
  447.   int i;                                 /* local index variable */
  448.  
  449.   /* If allocated, Free the XLATE structure memory */
  450.   if(XlateBase)
  451.   {
  452.     node = XlateBase;                    /* Establish node pointer */
  453.     for(i = 0; i < XlateLines; i++)      /* loop through table */
  454.     {
  455.       if(node->translate_key)            /* Check for allocation */
  456.         free(node->translate_key);       /* Free key memory */
  457.       if(node->translated_value)         /* Check for allocation */
  458.         free(node->translated_value);    /* Free value memory */
  459.       node++;                            /* Bump the Table pointer */
  460.     }
  461.  
  462.     free(XlateBase);                     /* Free the Base memory */
  463.     XlateBase = NULL;                    /* Reset base to NULL */
  464.   }
  465.   return;
  466. } /* end function 'XlateFree()' */
  467.  
  468. /*====================================================*/
  469.   int XlateSearchCompare(const void *a, const void *b)
  470. /*====================================================*/
  471. /* Compare function for searching the Translation Block. */
  472. {
  473.   return(strcmp((char *) a, ((XLATE *) b)->translate_key));
  474.  
  475. } /* end function 'XlateSearchCompare()' */
  476.  
  477. /*==================================================*/
  478.   int XlateSortCompare(const void *a, const void *b)
  479. /*==================================================*/
  480. /* Compare function for sorting the Translation Block. */
  481. {
  482.   return(strcmp(((XLATE *) a)->translate_key,
  483.                 ((XLATE *) b)->translate_key));
  484.  
  485. } /* end function 'XlateSortCompare()' */
  486.  
  487. /* end source file 'xlate.c' */
  488.